import { logger } from '$common';
import { AgentState } from './state';
import { SimulationJobController, SimulationModelController, SimulationRequest, ModelParseParamRequest, StopJobRequest } from '$domain/model/simulation';

export type ACK = (data: any) => void;
export type SocketIOHandler = (data: any, ack?: ACK) => void;
export class RunningState extends AgentState {

  private static _instance: RunningState;

  public static get Instance(): RunningState {
    if (!this._instance) {
      this._instance = new RunningState();
    }
    return this._instance;
  }

  private constructor() { super('running'); }

  async establishConnection() { this.warnJump(); }
  async registerAbilities() { this.warnJump(); }

  private addListener(eventName: string, fn: SocketIOHandler) {
    const connection = this.context.getSocketConnection();
    if (connection.hasListeners(eventName)) {
      logger.debug(`The ${eventName} listener has been added.`);
    } else {
      connection.on(eventName, fn);
    }
  }

  async onSimulationRequest() {
    this.addListener('simulation:run', async (request: SimulationRequest, ack: ACK) => {
      ack('ok'); // the gateway is notified to confirm that the job is successfully assigned, otherwise it will continue to dispatch requests
      await SimulationJobController.run(request);
    });

    this.addListener('simulation:stop', async (request: StopJobRequest, ack: ACK) => {
      await SimulationJobController.stop(request.jobId, request.modelBack || false);
    });

    this.addListener('model:parseParam', async (request: ModelParseParamRequest, ack: ACK) => {
      ack(await SimulationModelController.parseModelParam(request));
    });

    this.addListener('model:fileTrees', async (modelFilePath: string, ack: ACK) => {
      ack(await SimulationModelController.getModelFileTrees(modelFilePath));
    });

    this.addListener('simulation:query', async (ids: string[], ack: ACK) => {
      ack(await SimulationJobController.queryJobStatus(ids));
    });

    this.addListener('simulation:restart', async (request: SimulationRequest, ack: ACK) => {
      ack('ok'); // the gateway is notified to confirm that the job is successfully assigned, otherwise it will continue to dispatch requests
      await SimulationJobController.restart(request);
    });

  }
}